//The MIT License
//
//Copyright (c) 2009 nodchip
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
package tv.dyndns.kishibe.client.chat;

import java.util.Date;

import tv.dyndns.kishibe.client.Constant;
import tv.dyndns.kishibe.client.Controller;
import tv.dyndns.kishibe.client.Sanitize;
import tv.dyndns.kishibe.client.Service;
import tv.dyndns.kishibe.client.SharedData;
import tv.dyndns.kishibe.client.UserData;
import tv.dyndns.kishibe.client.Utility;
import tv.dyndns.kishibe.client.packet.PacketChatData;
import tv.dyndns.kishibe.client.setting.PanelSettingChat;
import tv.dyndns.kishibe.client.util.SerialTimer;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class PanelChat extends VerticalPanel implements KeyDownHandler, ClickHandler {
	public static final int MAX_RES = 50;
	public static final int DURATION = 5000;
	private final HorizontalPanel form = new HorizontalPanel();
	private final TextBox textBoxName;
	private final TextBox textBoxBody;
	private final Button buttonSend;
	private int lastestArrayIndex = 0;
	private final Timer timerRecieveMessage = new SerialTimer() {
		public void run() {
			recieveMessage();
		}
	};
	private boolean isRecieving = false;

	public PanelChat() {
		setWidth("800px");

		add(new Label("簡易チャット(設定画面から表示をON/OFFできます)"));

		textBoxName = new TextBox();
		textBoxName.setWidth("130px");
		textBoxName.setMaxLength(6);
		textBoxName.setText(UserData.getInstance().getPlayerName());

		textBoxBody = new TextBox();
		textBoxBody.setWidth("600px");
		textBoxBody.setMaxLength(50);
		textBoxBody.addKeyDownHandler(this);

		buttonSend = new Button("送信", this);

		form.add(textBoxName);
		form.add(textBoxBody);
		form.add(buttonSend);

		add(form);
	}

	private void sendMessage() {
		if (!checkContents()) {
			return;
		}

		setEnabled(false);

		final UserData record = UserData.getInstance();
		final PacketChatData chatData = new PacketChatData();
		chatData.name = textBoxName.getText();
		chatData.body = textBoxBody.getText();
		chatData.imageFileName = record.getImageFileName();
		chatData.classLevel = record.getClassLevel();
		chatData.userCode = record.getUserCode();

		Service.Util.getInstance().sendMessageToChat(chatData, callbackSendMessage);
	}

	private final AsyncCallback<Object> callbackSendMessage = new AsyncCallback<Object>() {
		public void onSuccess(Object result) {
			textBoxBody.setText("");
			setEnabled(true);
			textBoxBody.setFocus(false);
			textBoxBody.setFocus(true);
			recieveMessage();
		}

		public void onFailure(Throwable caught) {
			Controller.getInstance().showErrorMessage("PanelChat.sendMessage() - チャットメッセージの送信に失敗しました。");
		}
	};

	private boolean checkContents() {
		if (textBoxName.getText().trim().length() == 0) {
			return false;
		}

		if (textBoxBody.getText().trim().length() == 0) {
			return false;
		}

		return true;
	}

	private void recieveMessage() {
		if (isRecieving) {
			return;
		}
		isRecieving = true;

		Service.Util.getInstance().receiveMessageFromChat(lastestArrayIndex, callbackRecieveMessage);
	}

	private final AsyncCallback<PacketChatData[]> callbackRecieveMessage = new AsyncCallback<PacketChatData[]>() {
		public void onSuccess(PacketChatData[] result) {
			if (result != null && lastestArrayIndex != result[result.length - 1].resId) {
				lastestArrayIndex = result[result.length - 1].resId;
				addMessageToPanel(result);
			}

			isRecieving = false;
		}

		public void onFailure(Throwable caught) {
			caught.printStackTrace();
		}
	};

	private void addMessageToPanel(PacketChatData chatDatas[]) {
		lastestArrayIndex = chatDatas[chatDatas.length - 1].resId;

		final int myUserCode = UserData.getInstance().getUserCode();
		for (int i = 0; i < chatDatas.length; ++i) {

			final PacketChatData data = chatDatas[i];
			if (data == null) {
				continue;
			}

			// ユーザーコードが無視対象で、かつ自分が無視されていないときのみ表示する
			if (SharedData.getInstance().isIgnoreUserCode(data.userCode) && !SharedData.getInstance().isIgnoreUserCode(myUserCode)) {
				continue;
			}

			final HorizontalPanel panel = new HorizontalPanel();

			final Image image = new Image(Constant.ICON_URL_PREFIX + data.imageFileName);
			image.setPixelSize(Constant.ICON_SIZE, Constant.ICON_SIZE);
			panel.add(image);

			final VerticalPanel panelLog = new VerticalPanel();
			panelLog.setWidth("100%");

			final Date date = data.date;

			final StringBuffer upper = new StringBuffer();
			upper.append(data.resId);
			upper.append(" ");
			upper.append(Sanitize.getInstance().html(data.name));
			upper.append(Utility.getInstance().makeTrip(data.userCode, data.machineIp));
			upper.append(" ");

			upper.append(Utility.getInstance().toDateFormat(date));

			upper.append(" (").append(data.classLevel).append(")");

			final HTML upperHTML = new HTML(upper.toString());
			upperHTML.setWidth("680px");
			panelLog.add(upperHTML);

			final HTML lowerHTML = new HTML(Sanitize.getInstance().html(data.body));
			lowerHTML.setWidth("680px");
			panelLog.add(lowerHTML);

			panel.add(panelLog);

			panel.add(new Button("無視", new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					if (Window.confirm("OKボタンを押すと以降「" + data.name + "」さんの発言を表示しません。よろしいですか？")) {
						SharedData.getInstance().addUserIgnoreUserCode(data.userCode);
						PanelSettingChat.getInstance().addIgnoreUserCodeButton(data.userCode);
						final Button button = (Button) event.getSource();
						button.setEnabled(false);
					}
				}
			}));

			insert(panel, 2);
			while (getWidgetCount() > MAX_RES + 2) {
				remove(getWidgetCount() - 1);
			}
		}
	}

	public void onClick(Widget sender) {
		if (sender == buttonSend) {
			sendMessage();
		}
	}

	public void setEnabled(boolean enabled) {
		textBoxName.setEnabled(enabled);
		textBoxBody.setEnabled(enabled);
		buttonSend.setEnabled(enabled);
	}

	protected void onLoad() {
		super.onLoad();
		recieveMessage();
		timerRecieveMessage.scheduleRepeating(DURATION);
	}

	protected void onUnload() {
		timerRecieveMessage.cancel();
		super.onUnload();
	}

	@Override
	public void onKeyDown(KeyDownEvent event) {
		if (event.getSource() == textBoxBody) {
			if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
				sendMessage();
			}
		}
	}

	@Override
	public void onClick(ClickEvent event) {
		// TODO Auto-generated method stub

	}
}
